#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_err.h"
#include "esp_log.h"

#include "epd_driver.h"
#include "epd_font.h"
#include "epd_lvgl.h"
#include "lvgl.h"

#define EPD_LVGL_TICK_PERIOD_MS 2
#define EPD_LVGL_TAG "EPD Lvgl"

uint32_t image_size = EPD_7IN5BC_WIDTH * EPD_7IN5BC_HEIGHT;

static lv_disp_draw_buf_t disp_buf;
static lv_disp_drv_t disp_drv;
lv_disp_t *disp;
static lv_obj_t *scr;

void epd_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_map)
{
  epd_send_command(0x10);
  for (int y = area->y1; y <= area->y2; y++)
    for (int x = area->x1; x <= area->x2; x++)
    {
      lv_color_t color_temp = color_map[y * EPD_7IN5BC_WIDTH + x];
      uint8_t data = 0x00;
      if (color_temp.full == 0x00)
        data = 0x00;
      else if (color_temp.full == 0xe0)
        data = 0x04;
      else if (color_temp.full == 0xff)
        data = 0x03;

      data = (data << 4) & 0xFF;
      color_temp = color_map[y * EPD_7IN5BC_WIDTH + (++x)];

      if (color_temp.full == 0x00)
        data |= 0x00;
      else if (color_temp.full == 0xe0)
        data |= 0x04;
      else if (color_temp.full == 0xff)
        data |= 0x03;

      epd_send_data(data);
    }
  epd_display();

  lv_disp_flush_ready(disp);
}

static void epd_lvgl_increase_tick(void *arg)
{
  lv_tick_inc(EPD_LVGL_TICK_PERIOD_MS);
}

static void epd_lvgl_task(void *arg)
{

  for (;;)
  {
    vTaskDelay(10 / portTICK_PERIOD_MS);
    lv_timer_handler();
  }
}

void wday_create()
{
  lv_obj_t *wday = lv_obj_create(scr);
  lv_obj_set_size(wday, 640, 30);
  lv_obj_set_pos(wday, 0, 64);
  lv_obj_set_style_radius(wday, 0, LV_PART_MAIN);
  lv_obj_set_style_border_width(wday, 0, LV_PART_MAIN);
  lv_obj_set_style_bg_color(wday, lv_color_black(), LV_PART_MAIN);

  lv_obj_t *mon = lv_label_create(wday);
  lv_label_set_text(mon, "一");
  lv_obj_set_pos(mon, 128, -9);
  lv_obj_set_style_text_align(mon, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(mon, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(mon, lv_color_white(), LV_PART_MAIN);

  lv_obj_t *tue = lv_label_create(wday);
  lv_label_set_text(tue, "二");
  lv_obj_set_pos(tue, 220, -9);
  lv_obj_set_style_text_align(tue, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(tue, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(tue, lv_color_white(), LV_PART_MAIN);

  lv_obj_t *wed = lv_label_create(wday);
  lv_label_set_text(wed, "三");
  lv_obj_set_pos(wed, 312, -9);
  lv_obj_set_style_text_align(wed, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(wed, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(wed, lv_color_white(), LV_PART_MAIN);

  lv_obj_t *thu = lv_label_create(wday);
  lv_label_set_text(thu, "四");
  lv_obj_set_pos(thu, 404, -9);
  lv_obj_set_style_text_align(thu, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(thu, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(thu, lv_color_white(), LV_PART_MAIN);

  lv_obj_t *fri = lv_label_create(wday);
  lv_label_set_text(fri, "五");
  lv_obj_set_pos(fri, 496, -9);
  lv_obj_set_style_text_align(thu, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(fri, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(fri, lv_color_white(), LV_PART_MAIN);

  lv_obj_t *sat = lv_label_create(wday);
  lv_label_set_text(sat, "六");
  lv_obj_set_pos(sat, 588, -9);
  lv_obj_set_style_text_align(thu, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(sat, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(sat, lv_color_make(255, 0, 0), LV_PART_MAIN);

  lv_obj_t *sun = lv_label_create(wday);
  lv_label_set_text(sun, "日");
  lv_obj_set_pos(sun, 36, 3);
  lv_obj_set_style_text_align(thu, LV_ALIGN_CENTER, LV_PART_MAIN);
  lv_obj_set_style_text_font(sun, &heiti_16, LV_PART_MAIN);
  lv_obj_set_style_text_color(sun, lv_color_make(255, 0, 0), LV_PART_MAIN);
  lv_obj_set_style_border_width(sun, 1, LV_PART_MAIN);
  lv_obj_set_style_border_color(sun, lv_color_white(), LV_PART_MAIN);
}

void date_create(char *western_calendar, char *chinese_calendar, bool is_taday, int x, int y)
{
  lv_obj_t *date = lv_obj_create(scr);
  lv_obj_set_size(date, 90, 56);
  lv_obj_set_pos(date, x, y);
  lv_obj_set_style_radius(date, 0, LV_PART_MAIN);
  lv_obj_set_style_border_width(date, 1, LV_PART_MAIN);
  lv_obj_set_style_border_color(date, lv_color_black(), LV_PART_MAIN);

  lv_color_t color_font = is_taday ? lv_color_make(255, 0, 0) : lv_color_black();

  lv_obj_t *date_w = lv_obj_create(date);
  lv_obj_set_size(date_w, 90, 30);
  lv_obj_set_pos(date_w, 0, 0);
  lv_obj_set_style_radius(date_w, 0, LV_PART_MAIN);
  lv_obj_set_style_border_width(date_w, 1, LV_PART_MAIN);
  lv_obj_set_style_border_color(date_w, lv_color_black(), LV_PART_MAIN);

  lv_obj_t *wes = lv_label_create(date_w);
  lv_label_set_text(wes, western_calendar);
  lv_obj_set_width(wes, LV_SIZE_CONTENT);
  // lv_obj_align(wes, LV_ALIGN_CENTER, 0, 0);
  lv_obj_set_style_text_font(wes, &heiti_24, LV_PART_MAIN);
  lv_obj_set_style_text_color(wes, color_font, LV_PART_MAIN);

  // lv_obj_t *date_c = lv_obj_create(date);
  // lv_obj_set_size(date_c, 90, 20);
  // lv_obj_set_pos(date_c, 0, 36);
  // lv_obj_set_style_radius(date_c, 0, LV_PART_MAIN);
  // lv_obj_set_style_border_width(date_c, 0, LV_PART_MAIN);

  // lv_obj_t *chi = lv_label_create(date_c);
  // lv_label_set_text(chi, chinese_calendar);
  // lv_obj_set_width(chi, LV_SIZE_CONTENT);
  // lv_obj_align(chi, LV_ALIGN_CENTER, 0, 0);
  // lv_obj_set_style_text_align(chi, LV_ALIGN_CENTER, LV_PART_MAIN);
  // lv_obj_set_style_text_font(chi, &heiti_12, LV_PART_MAIN);
  // lv_obj_set_style_text_color(chi, color_font, LV_PART_MAIN);
}

void epd_lvgl_init()
{
  epd_init();
  // epd_clear();
  lv_init();

  lv_color_t *buf1 = heap_caps_malloc(image_size * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
  lv_disp_draw_buf_init(&disp_buf, buf1, NULL, image_size);

  ESP_LOGI(EPD_LVGL_TAG, "Register display driver to LVGL");
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = EPD_7IN5BC_WIDTH;
  disp_drv.ver_res = EPD_7IN5BC_HEIGHT;
  disp_drv.flush_cb = epd_flush;
  disp_drv.draw_buf = &disp_buf;
  disp = lv_disp_drv_register(&disp_drv);

  ESP_LOGI(EPD_LVGL_TAG, "Install LVGL tick timer");
  const esp_timer_create_args_t lvgl_tick_timer_args = {
      .callback = &epd_lvgl_increase_tick,
      .name = "epd_lvgl_tick"};

  esp_timer_handle_t lvgl_tick_timer = NULL;
  ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
  ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EPD_LVGL_TICK_PERIOD_MS * 1000));

  scr = lv_disp_get_scr_act(disp);

  wday_create();
  // date_create("1", "初一", true, 0, 94);
  // date_create("28", "二十一", false, 91, 94);

  lv_disp_flush_ready(&disp_drv);

  for (int i = 0; i < 100; i++)
  {
    vTaskDelay(10 / portTICK_PERIOD_MS);
    lv_timer_handler();
  }

  epd_exit();
  // xTaskCreate(epd_lvgl_task, "epd_lvgl_task", 20480, NULL, 10, NULL);
}

void epd_lvgl_disp_flush()
{
  lv_disp_flush_ready(&disp_drv);
}

void epd_lvgl_exit()
{
  epd_exit();
}